<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>Abel&#39;Blog</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta property="og:type" content="website">
<meta property="og:title" content="Abel&#39;Blog">
<meta property="og:url" content="http://example.com/index.html">
<meta property="og:site_name" content="Abel&#39;Blog">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="Abel Sean">
<meta name="twitter:card" content="summary">
  
    <link rel="alternate" href="/atom.xml" title="Abel&#39;Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  
<link rel="stylesheet" href="/css/style.css">

<meta name="generator" content="Hexo 5.4.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Abel&#39;Blog</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://example.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main">
  
    <article id="post-2021/2021-07-19-etcd-learn" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/07/19/2021/2021-07-19-etcd-learn/" class="article-date">
  <time datetime="2021-07-18T16:00:00.000Z" itemprop="datePublished">2021-07-19</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/07/19/2021/2021-07-19-etcd-learn/">go-etcd阅读笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h1 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://github.com/coreos/etcd/">go-ethereum</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/07/19/2021/2021-07-19-etcd-learn/" data-id="ckrn3an7j001x20xwa9dfc3la" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Go/" rel="tag">Go</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Server/" rel="tag">Server</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-07-19-socketop-learn" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/07/19/2021/2021-07-19-socketop-learn/" class="article-date">
  <time datetime="2021-07-18T16:00:00.000Z" itemprop="datePublished">2021-07-19</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/07/19/2021/2021-07-19-socketop-learn/">REUSEPORT-REUSEADDR-学习</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h1 id="准备知识"><a href="#准备知识" class="headerlink" title="准备知识"></a>准备知识</h1><h2 id="如何查看系统的版本"><a href="#如何查看系统的版本" class="headerlink" title="如何查看系统的版本"></a>如何查看系统的版本</h2><p>[root@test-qingzhou-01 ~]# hostnamectl<br>   Static hostname: test-qingzhou-01<br>         Icon name: computer-vm<br>           Chassis: vm<br>        Machine ID: 20190711105006363114529432776998<br>           Boot ID: 2abf6a175d9e4dc4a16c0b28d262818b<br>    Virtualization: kvm<br>  Operating System: CentOS Linux 7 (Core)<br>       CPE OS Name: cpe:/o:centos:centos:7<br>            Kernel: Linux 3.10.0-957.21.3.el7.x86_64<br>      Architecture: x86-64</p>
<h2 id="相关的系统调用"><a href="#相关的系统调用" class="headerlink" title="相关的系统调用"></a>相关的系统调用</h2><p>golang中的系统调用</p>
<figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))</span><br></pre></td></tr></table></figure>

<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">setsockopt</span><br></pre></td></tr></table></figure>

<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://stackoverflow.com/questions/14388706/how-do-so-reuseaddr-and-so-reuseport-differ">StackOverflow-SO_REUSEPORT-SO_REUSEADDR</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://www.jianshu.com/p/141aa1c41f15">SO_REUSEADDR和SO_REUSEPORT作用</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/07/19/2021/2021-07-19-socketop-learn/" data-id="ckrn3an7l002120xwhhs9awjq" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Go/" rel="tag">Go</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Server/" rel="tag">Server</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-06-22-go-ethereum-learn" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/06/22/2021/2021-06-22-go-ethereum-learn/" class="article-date">
  <time datetime="2021-06-21T16:00:00.000Z" itemprop="datePublished">2021-06-22</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/06/22/2021/2021-06-22-go-ethereum-learn/">go-ethereum阅读笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h1 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://github.com/ethereum/go-ethereum">go-ethereum</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/06/22/2021/2021-06-22-go-ethereum-learn/" data-id="ckrn3an7j001z20xwdgn093fk" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Go/" rel="tag">Go</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Server/" rel="tag">Server</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-06-21-server测试工具" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/06/21/2021/2021-06-21-server%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/" class="article-date">
  <time datetime="2021-06-20T16:00:00.000Z" itemprop="datePublished">2021-06-21</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/06/21/2021/2021-06-21-server%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/">server测试工具</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>记录一下常用的服务器测试工具。</p>
<h2 id="网络相关"><a href="#网络相关" class="headerlink" title="网络相关"></a>网络相关</h2><h3 id="抓包工具"><a href="#抓包工具" class="headerlink" title="抓包工具"></a>抓包工具</h3><p><a target="_blank" rel="noopener" href="https://blog.csdn.net/bandaoyu/article/details/107118729">网络分析</a></p>
<h4 id="wireshark-v3-4-5"><a href="#wireshark-v3-4-5" class="headerlink" title="wireshark_v3.4.5"></a>wireshark_v3.4.5</h4><h4 id="tcpdump"><a href="#tcpdump" class="headerlink" title="tcpdump"></a>tcpdump</h4><p>通过指令安装<code>yum install tcpdump</code>。</p>
<figure class="highlight zsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">$ tcpdump  -XvvennSs 0 -i enp2s0 port 8080</span><br><span class="line"></span><br><span class="line">20:01:34.640787 94:c6:91:57:e4:1b &gt; d4:5d:64:f0:76:aa, ethertype IPv4 (0x0800), length 54: (tos 0x0, ttl 64, id 23026, offset 0, flags [DF], proto TCP (6), length 40)</span><br><span class="line">    192.168.125.213.8080 &gt; 192.168.125.196.11743: Flags [.], cksum 0x7f69 (correct), seq 2141321887, ack 3936026461, win 471, length 0</span><br><span class="line">	0x0000:  4500 0028 59f2 4000 4006 63f3 c0a8 7dd5  E..(Y.@.@.c...&#125;.</span><br><span class="line">	0x0010:  c0a8 7dc4 1f90 2ddf 7fa1 fa9f ea9a ff5d  ..&#125;...-........]</span><br><span class="line">	0x0020:  5010 01d7 7f69 0000                      P....i..</span><br><span class="line">20:01:34.648655 94:c6:91:57:e4:1b &gt; d4:5d:64:f0:76:aa, ethertype IPv4 (0x0800), length 415: (tos 0x0, ttl 64, id 23027, offset 0, flags [DF], proto TCP (6), length 401)</span><br><span class="line">    192.168.125.213.8080 &gt; 192.168.125.196.11743: Flags [P.], cksum 0xe9dc (correct), seq 2141321887:2141322248, ack 3936026461, win 471, length 361: HTTP, length: 361</span><br><span class="line">	HTTP/1.1 200 OK</span><br><span class="line">	Content-Type: application/json; charset=utf-8</span><br><span class="line">	Date: Mon, 21 Jun 2021 12:01:34 GMT</span><br><span class="line">	Content-Length: 237</span><br><span class="line">	</span><br><span class="line">	0x0000:  4500 0191 59f3 4000 4006 6289 c0a8 7dd5  E...Y.@.@.b...&#125;.</span><br><span class="line">	0x0010:  c0a8 7dc4 1f90 2ddf 7fa1 fa9f ea9a ff5d  ..&#125;...-........]</span><br><span class="line">	0x0020:  5018 01d7 e9dc 0000 4854 5450 2f31 2e31  P.......HTTP/1.1</span><br><span class="line">	0x0030:  2032 3030 204f 4b0d 0a43 6f6e 7465 6e74  .200.OK..Content</span><br><span class="line">	0x0090:  7465 6e74 2d4c 656e 6774 683a 2032 3337  tent-Length:.237</span><br><span class="line">	0x00a0:  0d0a 0d0a 7b22 5549 4422 3a34 372c 224c  ....&#123;<span class="string">&quot;UID&quot;</span>:47,<span class="string">&quot;L</span></span><br><span class="line"><span class="string">	0x00b0:  6f62 6279 4164 6472 223a 2231 3932 2e31  obbyAddr&quot;</span>:<span class="string">&quot;192.1</span></span><br><span class="line"><span class="string">	0x00c0:  3638 2e31 3235 2e31 3936 3a32 3636 3622  68.125.196:2666&quot;</span></span><br><span class="line">	0x0170:  3565 3436 3264 6331 3866 3963 3063 3661  5e462dc18f9c0c6a</span><br><span class="line">	0x0180:  3366 6439 6465 3261 3835 6538 6522 7d5d  3fd9de2a85e8e<span class="string">&quot;&#125;]</span></span><br><span class="line"><span class="string">	0x0190:  7d                                       </span></span><br></pre></td></tr></table></figure>

<p>所以，在工作中 tcpdump 只是用来抓取数据包，不用来分析数据包，而是把 tcpdump 抓取的数据包保存成 pcap 后缀的文件，接着用 Wireshark 工具进行数据包分析。</p>
<p>先使用指令将侦听到的数据写入文件，<code>tcpdump  -XvvennSs 0 -i enp2s0 port 8080 -w http_tcpdump.pcap</code>。然后使用wireshark来看。</p>
<p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/82498482">wireshark说明文档</a></p>
<h3 id="网络限制工具"><a href="#网络限制工具" class="headerlink" title="网络限制工具"></a>网络限制工具</h3><h4 id="TC"><a href="#TC" class="headerlink" title="TC"></a>TC</h4><p>TC是限速命令，<code>wondershaper</code>是国外人开发的一款在Linux内核下基于TC工具的对整块网卡的限度工具。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">yum install epel-release -y</span><br><span class="line">yum install wondershaper -y</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/cainiaoit/p/8582322.html">TC工具</a></p>
<h3 id="监控网络使用率"><a href="#监控网络使用率" class="headerlink" title="监控网络使用率"></a>监控网络使用率</h3><p>使用iftop工具能监控服务器通讯情况<code>yum install iftop</code>。</p>
<h3 id="网上找到的建议"><a href="#网上找到的建议" class="headerlink" title="网上找到的建议"></a>网上找到的建议</h3><p>ip：查看网卡上的总流量<br>来自 iproute2util 包，在大多数系统上都已经默认安装，也可通过 yum install -y iproute 安装<br>nload：查看各个网络设备的当前网络速率<br>来自EPEL软件库，安装：yum install -y epel-release &amp;&amp; yum install -y nload<br>iptraf-ng：可以输出网卡的tcp、udp等各种数据，和各个网卡的实时网速<br>默认未安装，可使用 yum install -y iptraf-ng 安装<br>stat：用来替换vmstat、iostat、netstat、nfsstat和ifstat的全能系统信息统计工具，支持数据实时刷新，输出直观易懂<br>默认没有安装，安装命令为：yum install -y dstat<br>sar：System Activity Report的缩写，是一款全面的Linux系统运行状态统计和性能分析工具，可从磁盘IO、CPU负载、内存使用等多个维度对系统活动进行报告<br>来自 sysstat 包，安装：yum install -y sysstat<br>ss 和 netstat：查看活动链接/监听端口的常用命令。ss 是 netstat 的替代，性能更好，建议使用<br>ss 是 iproute2util 包的一部分，netstat 来自 net-tools 包，新版系统上需要自行安装：yum install -y net-tools<br>nethogs：查看单个进程流量而设计的工具，按照进程进行带宽分组<br>来自EPEL软件库，安装命令是：yum install -y epel-release &amp;&amp; yum install -y nethogs<br>tcpdump：用来抓包，保存的数据可以用wireshark打开和查看</p>
<p>版权声明：本文为CSDN博主「guotianqing」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。<br><a target="_blank" rel="noopener" href="https://blog.csdn.net/guotianqing/article/details/109822561">原文链接</a></p>
<p><a target="_blank" rel="noopener" href="https://www.zhihu.com/question/19862245">Linux网络工具</a></p>
<p>nethogs: 按进程查看流量占用<br>iptraf: 按连接/端口查看流量<br>ifstat: 按设备查看流量<br>ethtool: 诊断工具<br>tcpdump: 抓包工具<br>ss: 连接查看工具<br>其他: dstat, slurm, nload, bmon</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/06/21/2021/2021-06-21-server%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/" data-id="ckrn3an7i001v20xwging3i4b" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Server/" rel="tag">Server</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-06-09-pprof-doc" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/06/09/2021/2021-06-09-pprof-doc/" class="article-date">
  <time datetime="2021-06-08T16:00:00.000Z" itemprop="datePublished">2021-06-09</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/06/09/2021/2021-06-09-pprof-doc/">go-pprof</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h1 id="pprof"><a href="#pprof" class="headerlink" title="pprof"></a>pprof</h1><p>pprof is a tool for visualization and analysis of profiling data.</p>
<p>pprof reads a collection of profiling samples in profile.proto format and<br>generates reports to visualize and help analyze the data. It can generate both<br>text and graphical reports (through the use of the dot visualization package).</p>
<p>profile.proto is a protocol buffer that describes a set of callstacks<br>and symbolization information. A common usage is to represent a set of<br>sampled callstacks from statistical profiling. The format is<br>described on the proto/profile.proto file. For details on protocol<br>buffers, see <a target="_blank" rel="noopener" href="https://developers.google.com/protocol-buffers">https://developers.google.com/protocol-buffers</a></p>
<p>Profiles can be read from a local file, or over http. Multiple<br>profiles of the same type can be aggregated or compared.</p>
<p>If the profile samples contain machine addresses, pprof can symbolize<br>them through the use of the native binutils tools (addr2line and nm).</p>
<h1 id="pprof-profiles"><a href="#pprof-profiles" class="headerlink" title="pprof profiles"></a>pprof profiles</h1><p>pprof operates on data in the profile.proto format. Each profile is a collection<br>of samples, where each sample is associated to a point in a location hierarchy,<br>one or more numeric values, and a set of labels. Often these profiles represents<br>data collected through statistical sampling of a program, so each sample<br>describes a program call stack and a number or value of samples collected at a<br>location. pprof is agnostic to the profile semantics, so other uses are<br>possible. The interpretation of the reports generated by pprof depends on the<br>semantics defined by the source of the profile.</p>
<h1 id="Usage-Modes"><a href="#Usage-Modes" class="headerlink" title="Usage Modes"></a>Usage Modes</h1><p>There are few different ways of using <code>pprof</code>.</p>
<h2 id="Report-generation"><a href="#Report-generation" class="headerlink" title="Report generation"></a>Report generation</h2><p>If a report format is requested on the command line:</p>
<pre><code>pprof &lt;format&gt; [options] source
</code></pre>
<p>pprof will generate a report in the specified format and exit.<br>Formats can be either text, or graphical. See below for details about<br>supported formats, options, and sources.</p>
<h2 id="Interactive-terminal-use"><a href="#Interactive-terminal-use" class="headerlink" title="Interactive terminal use"></a>Interactive terminal use</h2><p>Without a format specifier:</p>
<pre><code>pprof [options] source
</code></pre>
<p>pprof will start an interactive shell in which the user can type<br>commands.  Type <code>help</code> to get online help.</p>
<h2 id="Web-interface"><a href="#Web-interface" class="headerlink" title="Web interface"></a>Web interface</h2><p>If a host:port is specified on the command line:</p>
<pre><code>pprof -http=[host]:[port] [options] source
</code></pre>
<p>pprof will start serving HTTP requests on the specified port.  Visit<br>the HTTP url corresponding to the port (typically <code>http://&lt;host&gt;:&lt;port&gt;/</code>)<br>in a browser to see the interface.</p>
<h1 id="Details"><a href="#Details" class="headerlink" title="Details"></a>Details</h1><p>The objective of pprof is to generate a report for a profile. The report is<br>generated from a location hierarchy, which is reconstructed from the profile<br>samples. Each location contains two values: </p>
<ul>
<li><em>flat</em>: the value of the location itself.</li>
<li><em>cum</em>: the value of the location plus all its descendants. </li>
</ul>
<p>Samples that include a location multiple times (e.g. for recursive functions)<br>are counted only once per location.</p>
<h2 id="Options"><a href="#Options" class="headerlink" title="Options"></a>Options</h2><p><em>options</em> configure the contents of a report. Each option has a value,<br>which can be boolean, numeric, or strings. While only one format can<br>be specified, most options can be selected independently of each<br>other.</p>
<p>Some common pprof options are:</p>
<ul>
<li><strong>-flat</strong> [default], <strong>-cum</strong>: Sort entries based on their flat or cumulative<br>value respectively, on text reports.</li>
<li><strong>-functions</strong> [default], <strong>-filefunctions</strong>, <strong>-files</strong>, <strong>-lines</strong>,<br><strong>-addresses</strong>: Generate the report using the specified granularity.</li>
<li><strong>-noinlines</strong>: Attribute inlined functions to their first out-of-line caller.<br>For example, a command like <code>pprof -list foo -noinlines profile.pb.gz</code> can be<br>used to produce the annotated source listing attributing the metrics in the<br>inlined functions to the out-of-line calling line.</li>
<li><strong>-nodecount= <em>int</em>:</strong> Maximum number of entries in the report. pprof will<br>only print this many entries and will use heuristics to select which entries<br>to trim.</li>
<li><strong>-focus= <em>regex</em>:</strong> Only include samples that include a report entry matching<br><em>regex</em>.</li>
<li><strong>-ignore= <em>regex</em>:</strong> Do not include samples that include a report entry<br>matching <em>regex</em>.</li>
<li><strong>-show_from= <em>regex</em>:</strong> Do not show entries above the first one that<br>matches <em>regex</em>.</li>
<li><strong>-show= <em>regex</em>:</strong> Only show entries that match <em>regex</em>.</li>
<li><strong>-hide= <em>regex</em>:</strong> Do not show entries that match <em>regex</em>.</li>
</ul>
<p>Each sample in a profile may include multiple values, representing different<br>entities associated to the sample. pprof reports include a single sample value,<br>which by convention is the last one specified in the report. The <code>sample_index=</code><br>option selects which value to use, and can be set to a number (from 0 to the<br>number of values - 1) or the name of the sample value.</p>
<p>Sample values are numeric values associated to a unit. If pprof can recognize<br>these units, it will attempt to scale the values to a suitable unit for<br>visualization. The <code>unit=</code> option will force the use of a specific unit. For<br>example, <code>unit=sec</code> will force any time values to be reported in<br>seconds. pprof recognizes most common time and memory size units.</p>
<h2 id="Tag-filtering"><a href="#Tag-filtering" class="headerlink" title="Tag filtering"></a>Tag filtering</h2><p>Samples in a profile may have tags. These tags have a name and a value; this<br>value can be either numeric or a string. pprof can select samples from a<br>profile based on these tags using the <code>-tagfocus</code> and <code>-tagignore</code> options.</p>
<p>Generally, these options work as follows:</p>
<ul>
<li><strong>-tagfocus=<em>regex</em></strong> or <strong>-tagfocus=<em>range</em>:</strong> Restrict to samples with tags<br>matched by regexp or in range.</li>
<li><strong>-tagignore=<em>regex</em></strong> or <strong>-tagignore=<em>range</em>:</strong> Discard samples with tags<br>matched by regexp or in range.</li>
</ul>
<p>When using <code>-tagfocus=regex</code> and <code>-tagignore=regex</code>, the regex will be compared<br>to each value associated with each tag. If one specifies a value<br>like <code>regex1,regex2</code>, then only samples with a tag value matching <code>regex1</code><br>and a tag value matching <code>regex2</code> will be kept.</p>
<p>In addition to being able to filter on tag values, one can specify the name of<br>the tag which a certain value must be associated with using the notation<br><code>-tagfocus=tagName=value</code>. Here, the <code>tagName</code> must match the tag’s name<br>exactly, and the value can be either a regex or a range. If one specifies<br>a value like <code>regex1,regex2</code>, then samples with a tag value (paired with the<br>specified tag name) matching either <code>regex1</code> or matching <code>regex2</code> will match.</p>
<p>Here are examples explaining how <code>tagfocus</code> can be used:</p>
<ul>
<li><code>-tagfocus 128kb:512kb</code> accepts a sample iff it has any numeric tag with<br>memory value in the specified range.</li>
<li><code>-tagfocus mytag=128kb:512kb</code> accepts a sample iff it has a numeric tag<br><code>mytag</code> with memory value in the specified range. There isn’t a way to say<br> <code>-tagfocus mytag=128kb:512kb,16kb:32kb</code><br> or <code>-tagfocus mytag=128kb:512kb,mytag2=128kb:512kb</code>. Just single value or<br> range for numeric tags.</li>
<li><code>-tagfocus someregex</code> accepts a sample iff it has any string tag with<br><code>tagName:tagValue</code> string matching specified regexp. In the future, this<br>will change to accept sample iff it has any string tag with <code>tagValue</code> string<br>matching specified regexp.</li>
<li><code>-tagfocus mytag=myvalue1,myvalue2</code> matches if either of the two tag values<br>are present.</li>
</ul>
<p><code>-tagignore</code> works similarly, except that it discards matching samples, instead<br>of keeping them.</p>
<p>If both the <code>-tagignore</code> and <code>-tagfocus</code> expressions (either a regexp or a<br>range) match a given sample, then the sample will be discarded.</p>
<h2 id="Text-reports"><a href="#Text-reports" class="headerlink" title="Text reports"></a>Text reports</h2><p>pprof text reports show the location hierarchy in text format.</p>
<ul>
<li><strong>-text:</strong> Prints the location entries, one per line, including the flat and<br>cum values.</li>
<li><strong>-tree:</strong> Prints each location entry with its predecessors and successors.</li>
<li><strong>-peek= <em>regex</em>:</strong> Print the location entry with all its predecessors and<br>successors, without trimming any entries.</li>
<li><strong>-traces:</strong> Prints each sample with a location per line.</li>
</ul>
<h2 id="Graphical-reports"><a href="#Graphical-reports" class="headerlink" title="Graphical reports"></a>Graphical reports</h2><p>pprof can generate graphical reports on the DOT format, and convert them to<br>multiple formats using the graphviz package.</p>
<p>These reports represent the location hierarchy as a graph, with a report entry<br>represented as a node. Nodes are removed using heuristics to limit the size of<br>the graph, controlled by the <em>nodecount</em> option.</p>
<ul>
<li><strong>-dot:</strong> Generates a report in .dot format. All other formats are generated<br>from this one.</li>
<li><strong>-svg:</strong> Generates a report in SVG format.</li>
<li><strong>-web:</strong> Generates a report in SVG format on a temp file, and starts a web<br>browser to view it.</li>
<li><strong>-png, -jpg, -gif, -pdf:</strong> Generates a report in these formats.</li>
</ul>
<h3 id="Interpreting-the-Callgraph"><a href="#Interpreting-the-Callgraph" class="headerlink" title="Interpreting the Callgraph"></a>Interpreting the Callgraph</h3><ul>
<li><p><strong>Node Color</strong>:</p>
<ul>
<li>large positive cum values are red.（较大的正值为红色。）</li>
<li>large negative cum values are green.（较大的负值为绿色。）</li>
<li>cum values close to zero are grey.（接近零的累积值为灰色。）</li>
</ul>
</li>
<li><p><strong>Node Font Size</strong>:</p>
<ul>
<li>larger font size means larger absolute flat values.（较大的字体大小意味着较大的绝对单位值。）</li>
<li>smaller font size means smaller absolute flat values. （较小的字体大小意味着较小的绝对单位值。）</li>
</ul>
</li>
<li><p><strong>Edge Weight</strong>:</p>
<ul>
<li>thicker edges indicate more resources were used along that path.（较厚的边缘表明沿该路径使用了更多的资源。）</li>
<li>thinner edges indicate fewer resources were used along that path.（较薄的边缘表明沿该路径使用的资源较少。）</li>
</ul>
</li>
<li><p><strong>Edge Color</strong>:</p>
<ul>
<li>large positive values are red.</li>
<li>large negative values are green.</li>
<li>values close to zero are grey.</li>
</ul>
</li>
<li><p><strong>Dashed Edges</strong>（虚线）: some locations between the two connected locations were<br>removed.（两个连接位置之间的某些位置已被删除。）</p>
</li>
<li><p><strong>Solid Edges</strong>（实线）: one location directly calls the other.（一个位置直接调用另一个位置。）</p>
</li>
<li><p><strong>“(inline)” Edge Marker</strong>（带横线标记的线）: the call has been inlined into the caller.（调用者已内联到被调用者）</p>
</li>
</ul>
<p>Let’s consider the following example graph:</p>
<p><img src="images/callgraph.png" alt="callgraph"></p>
<ul>
<li><p>For nodes:</p>
<ul>
<li><code>(*Rand).Read</code> has a small flat value and a small cum value because the<br>the font is small and the node is grey.</li>
<li><code>(*compressor).deflate</code> has a large flat value and a large cum value because the font<br>is large and the node is red.</li>
<li><code>(*Writer).Flush</code> has a small flat value and a large cum value because the font is<br>small and the node is red.</li>
</ul>
</li>
<li><p>For edges:</p>
<ul>
<li>the edge between <code>(*Writer).Write</code> and <code>(*compressor).write</code>: <ul>
<li>Since it is a dashed edge, some nodes were removed between those two.</li>
<li>Since it is thick and red, more resources were used in call stacks between<br>those two nodes.</li>
</ul>
</li>
<li>the edge between <code>(*Rand).Read</code> and <code>read</code>:<ul>
<li>Since it is a dashed edge, some nodes were removed between those two.</li>
<li>Since it is thin and grey, fewer resources were used in call stacks<br>between those two nodes.</li>
</ul>
</li>
<li>the edge between <code>read</code> and <code>(*rngSource).Int63</code>:<ul>
<li>Since it is a solid edge, there are no nodes between those two (i.e. it<br>was a direct call).</li>
<li>Since it is thin and grey, fewer resources were used in call stacks<br>between those two nodes.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="Annotated-code"><a href="#Annotated-code" class="headerlink" title="Annotated code"></a>Annotated code</h2><p>pprof can also generate reports of annotated source with samples associated to<br>them. For these, the source or binaries must be locally available, and the<br>profile must contain data with the appropriate level of detail.</p>
<p>pprof will look for source files on its current working directory and all its<br>ancestors. pprof will look for binaries on the directories specified in the<br><code>$PPROF_BINARY_PATH</code> environment variable, by default <code>$HOME/pprof/binaries</code><br>(<code>%USERPROFILE%\pprof\binaries</code> on Windows). It will look binaries up by name,<br>and if the profile includes linker build ids, it will also search for them in<br>a directory named as the build id.</p>
<p>pprof uses the binutils tools to examine and disassemble the binaries. By<br>default it will search for those tools in the current path, but it can also<br>search for them in a directory pointed to by the environment variable<br><code>$PPROF_TOOLS</code>.</p>
<ul>
<li><strong>-list= <em>regex</em>:</strong> Generates an annotated source listing for functions<br>matching <em>regex</em>, with flat/cum values for each source line.</li>
<li><strong>-disasm= <em>regex</em>:</strong> Generates an annotated disassembly listing for<br>functions matching <em>regex</em>.</li>
<li><strong>-weblist= <em>regex</em>:</strong> Generates a source/assembly combined annotated listing<br>for functions matching <em>regex</em>, and starts a web browser to display it.</li>
</ul>
<h2 id="Comparing-profiles"><a href="#Comparing-profiles" class="headerlink" title="Comparing profiles"></a>Comparing profiles</h2><p>pprof can subtract one profile from another, provided the profiles are of<br>compatible types (i.e. two heap profiles). pprof has two options which can be<br>used to specify the filename or URL for a profile to be subtracted from the<br>source profile:</p>
<ul>
<li><p><strong>-diff_base= <em>profile</em>:</strong> useful for comparing two profiles. Percentages in<br>the output are relative to the total of samples in the diff base profile.</p>
</li>
<li><p><strong>-base= <em>profile</em>:</strong> useful for subtracting a cumulative profile, like a<br><a target="_blank" rel="noopener" href="https://golang.org/doc/diagnostics.html#profiling">golang block profile</a>,<br>from another cumulative profile collected from the same program at a later time.<br>When comparing cumulative profiles collected on the same program, percentages in<br>the output are relative to the difference between the total for the source<br>profile and the total for the base profile.</p>
</li>
</ul>
<p>The <strong>-normalize</strong> flag can be used when a base profile is specified with either<br>the <code>-diff_base</code> or the <code>-base</code> option. This flag scales the source profile so<br>that the total of samples in the source profile is equal to the total of samples<br>in the base profile prior to subtracting the base profile from the source<br>profile. Useful for determining the relative differences between profiles, for<br>example, which profile has a larger percentage of CPU time used in a particular<br>function.</p>
<p>When using the <strong>-diff_base</strong> option, some report entries may have negative<br>values. If the merged profile is output as a protocol buffer, all samples in the<br>diff base profile will have a label with the key “pprof::base” and a value of<br>“true”. If pprof is then used to look at the merged profile, it will behave as<br>if separate source and base profiles were passed in.</p>
<p>When using the <strong>-base</strong> option to subtract one cumulative profile from another<br>collected on the same program at a later time, percentages will be relative to<br>the difference between the total for the source profile and the total for<br>the base profile, and all values will be positive. In the general case, some<br>report entries may have negative values and percentages will be relative to the<br>total of the absolute value of all samples when aggregated at the address level.</p>
<h1 id="Fetching-profiles"><a href="#Fetching-profiles" class="headerlink" title="Fetching profiles"></a>Fetching profiles</h1><p>pprof can read profiles from a file or directly from a URL over http or https.<br>Its native format is a gzipped profile.proto file, but it can<br>also accept some legacy formats generated by<br><a target="_blank" rel="noopener" href="https://github.com/gperftools/gperftools">gperftools</a>.</p>
<p>When fetching from a URL handler, pprof accepts options to indicate how much to<br>wait for the profile.</p>
<ul>
<li><strong>-seconds= <em>int</em>:</strong> Makes pprof request for a profile with the specified<br>duration in seconds. Only makes sense for profiles based on elapsed time, such<br>as CPU profiles.</li>
<li><strong>-timeout= <em>int</em>:</strong> Makes pprof wait for the specified timeout when<br>retrieving a profile over http. If not specified, pprof will use heuristics to<br>determine a reasonable timeout.</li>
</ul>
<p>pprof also accepts options which allow a user to specify TLS certificates to<br>use when fetching or symbolizing a profile from a protected endpoint. For more<br>information about generating these certificates, see<br><a target="_blank" rel="noopener" href="https://docs.docker.com/engine/security/https/">https://docs.docker.com/engine/security/https/</a>.</p>
<ul>
<li><strong>-tls_cert= <em>/path/to/cert</em>:</strong> File containing the TLS client certificate<br>to be used when fetching and symbolizing profiles.</li>
<li><strong>-tls_key= <em>/path/to/key</em>:</strong> File containing the TLS private key to be used<br>when fetching and symbolizing profiles.</li>
<li><strong>-tls_ca= <em>/path/to/ca</em>:</strong> File containing the certificate authority to be<br>used when fetching and symbolizing profiles.</li>
</ul>
<p>pprof also supports skipping verification of the server’s certificate chain and<br>host name when collecting or symbolizing a profile. To skip this verification,<br>use “https+insecure” in place of “https” in the URL.</p>
<p>If multiple profiles are specified, pprof will fetch them all and merge<br>them. This is useful to combine profiles from multiple processes of a<br>distributed job. The profiles may be from different programs but must be<br>compatible (for example, CPU profiles cannot be combined with heap profiles).</p>
<h2 id="Symbolization"><a href="#Symbolization" class="headerlink" title="Symbolization"></a>Symbolization</h2><p>pprof can add symbol information to a profile that was collected only with<br>address information. This is useful for profiles for compiled languages, where<br>it may not be easy or even possible for the profile source to include function<br>names or source coordinates.</p>
<p>pprof can extract the symbol information locally by examining the binaries using<br>the binutils tools, or it can ask running jobs that provide a symbolization<br>interface.</p>
<p>pprof will attempt symbolizing profiles by default, and its <code>-symbolize</code> option<br>provides some control over symbolization:</p>
<ul>
<li><p><strong>-symbolize=none:</strong> Disables any symbolization from pprof.</p>
</li>
<li><p><strong>-symbolize=local:</strong> Only attempts symbolizing the profile from local<br>binaries using the binutils tools.</p>
</li>
<li><p><strong>-symbolize=remote:</strong> Only attempts to symbolize running jobs by contacting<br>their symbolization handler.</p>
</li>
</ul>
<p>For local symbolization, pprof will look for the binaries on the paths specified<br>by the profile, and then it will search for them on the path specified by the<br>environment variable <code>$PPROF_BINARY_PATH</code>. Also, the name of the main binary can<br>be passed directly to pprof as its first parameter, to override the name or<br>location of the main binary of the profile, like this:</p>
<pre><code>pprof /path/to/binary profile.pb.gz
</code></pre>
<p>By default pprof will attempt to demangle and simplify C++ names, to provide<br>readable names for C++ symbols. It will aggressively discard template and<br>function parameters. This can be controlled with the <code>-symbolize=demangle</code><br>option. Note that for remote symbolization mangled names may not be provided by<br>the symbolization handler.</p>
<ul>
<li><p><strong>-symbolize=demangle=none:</strong> Do not perform any demangling. Show mangled<br>names if available.</p>
</li>
<li><p><strong>-symbolize=demangle=full:</strong> Demangle, but do not perform any<br>simplification. Show full demangled names if available.</p>
</li>
<li><p><strong>-symbolize=demangle=templates:</strong> Demangle, and trim function parameters, but<br>not template parameters.</p>
</li>
</ul>
<h1 id="Web-Interface"><a href="#Web-Interface" class="headerlink" title="Web Interface"></a>Web Interface</h1><p>When the user requests a web interface (by supplying an <code>-http=[host]:[port]</code><br>argument on the command-line), pprof starts a web server and opens a browser<br>window pointing at that server. The web interface provided by the server allows<br>the user to interactively view profile data in multiple formats.</p>
<p>The top of the display is a header that contains some buttons and menus.</p>
<h2 id="Config"><a href="#Config" class="headerlink" title="Config"></a>Config</h2><p>The <code>Config</code> menu allows the user to save the current refinement<br>settings (e.g., the focus and hide list) as a named configuration. A<br>saved configuration can later be re-applied to reinstitue the saved<br>refinements. The <code>Config</code> menu contains:</p>
<p><strong>Save as …</strong>: shows a dialog where the user can type in a<br>configuration name. The current refinement settings are saved under<br>the specified name.</p>
<p><strong>Default</strong>: switches back to the default view by removing all refinements.</p>
<p>The <code>Config</code> menu also contains an entry per named<br>configuration. Selecting such an entry applies that configuration. The<br>currently selected entry is marked with a ✓. Clicking on the 🗙 on the<br>right-hand side of such an entry deletes the configuration (after<br>prompting the user to confirm).</p>
<h2 id="TODO-cover-the-following-issues"><a href="#TODO-cover-the-following-issues" class="headerlink" title="TODO: cover the following issues:"></a>TODO: cover the following issues:</h2><ul>
<li>  Overall layout</li>
<li>  Menu entries</li>
<li>  Explanation of all the views</li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/06/09/2021/2021-06-09-pprof-doc/" data-id="ckrn3an7s002m20xweejl00rq" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Server/" rel="tag">Server</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-04-19-c++-metaprogramming" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/04/19/2021/2021-04-19-c++-metaprogramming/" class="article-date">
  <time datetime="2021-04-18T16:00:00.000Z" itemprop="datePublished">2021-04-19</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/04/19/2021/2021-04-19-c++-metaprogramming/">c++metaprogramming</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h1 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h1><p>元编程（template meta-programming），在许多现代C++和Boost程序组件里面使用了。如果不能理解这块的东西，将无法读懂很多代码。可以通过它操作产生程序的程序。元编程是工作在编译器级别的一种程序。和普通编程不相同，普通编程是在执行的时候，对变量计算、判断和赋值；元编程是泛型编程的子集。</p>
<h2 id="语法元素"><a href="#语法元素" class="headerlink" title="语法元素"></a>语法元素</h2><h2 id="元数据（meta-data）"><a href="#元数据（meta-data）" class="headerlink" title="元数据（meta data）"></a>元数据（meta data）</h2><h2 id="元函数（meta-function）"><a href="#元函数（meta-function）" class="headerlink" title="元函数（meta function）"></a>元函数（meta function）</h2><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://bot-man-jl.github.io/articles/?post=2017/Cpp-Metaprogramming">浅谈 C++ 元编程</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://github.com/boostorg/hana">Boost. Your standard library for metaprogramming EB/OL</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/04/19/2021/2021-04-19-c++-metaprogramming/" data-id="ckrn3an7i001t20xw59an7k8q" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/C/" rel="tag">C++</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-04-15-c++17-filesystem" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/04/15/2021/2021-04-15-c++17-filesystem/" class="article-date">
  <time datetime="2021-04-14T16:00:00.000Z" itemprop="datePublished">2021-04-15</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/04/15/2021/2021-04-15-c++17-filesystem/">c++17-filesystem</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>记录一下filesystem相关知识，需要开启c++17标准。</p>
<h1 id="path相关操作"><a href="#path相关操作" class="headerlink" title="path相关操作"></a>path相关操作</h1><h2 id="目录操作"><a href="#目录操作" class="headerlink" title="目录操作"></a>目录操作</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取绝对路径</span></span><br><span class="line">std::filesystem::<span class="built_in">absolute</span>(std::filesystem::<span class="built_in">current_path</span>().<span class="built_in">append</span>(filename_));</span><br><span class="line"><span class="comment">// 获得目录分割</span></span><br><span class="line">std::filesystem::path::preferred_separator;</span><br></pre></td></tr></table></figure>

<h2 id="遍历目录"><a href="#遍历目录" class="headerlink" title="遍历目录"></a>遍历目录</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;fstream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;filesystem&gt;</span></span></span><br><span class="line"><span class="keyword">namespace</span> fs = std::filesystem;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    fs::<span class="built_in">create_directories</span>(<span class="string">&quot;sandbox/a/b&quot;</span>);</span><br><span class="line">    std::<span class="built_in">ofstream</span>(<span class="string">&quot;sandbox/file1.txt&quot;</span>);</span><br><span class="line">    std::<span class="built_in">ofstream</span>(<span class="string">&quot;sandbox/file2.txt&quot;</span>);</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">auto</span>&amp; p: fs::<span class="built_in">directory_iterator</span>(<span class="string">&quot;sandbox&quot;</span>))</span><br><span class="line">        std::cout &lt;&lt; p.<span class="built_in">path</span>() &lt;&lt; <span class="string">&#x27;\n&#x27;</span>;</span><br><span class="line">    fs::<span class="built_in">remove_all</span>(<span class="string">&quot;sandbox&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">output:</span><br><span class="line"><span class="string">&quot;sandbox/a&quot;</span></span><br><span class="line"><span class="string">&quot;sandbox/file1.txt&quot;</span></span><br><span class="line"><span class="string">&quot;sandbox/file2.txt&quot;</span></span><br></pre></td></tr></table></figure>

<h2 id="获取文件名"><a href="#获取文件名" class="headerlink" title="获取文件名"></a>获取文件名</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> log_path = fs::<span class="built_in">absolute</span>(log_path_).<span class="built_in">string</span>();</span><br><span class="line"><span class="keyword">auto</span> logger_name = fs::<span class="built_in">path</span>(log_path).<span class="built_in">stem</span>().<span class="built_in">string</span>();</span><br></pre></td></tr></table></figure>

<h1 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h1><ul>
<li>[1]<a target="_blank" rel="noopener" href="https://en.cppreference.com/w/cpp/filesystem">Filesystem library</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/04/15/2021/2021-04-15-c++17-filesystem/" data-id="ckrn3an7h001r20xwciayh2lg" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/C/" rel="tag">C++</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-03-29-C++内存泄漏问题定位" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/03/29/2021/2021-03-29-C++%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D/" class="article-date">
  <time datetime="2021-03-28T16:00:00.000Z" itemprop="datePublished">2021-03-29</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/03/29/2021/2021-03-29-C++%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D/">c++内存泄漏问题定位</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>C++非常容易出现内存泄漏的问题。写一篇文章来总结这块的事情。</p>
<p>内存泄漏和内存野指针，是相伴随出现的。本质来自于堆内存处理的粗暴造成。</p>
<h1 id="工具篇"><a href="#工具篇" class="headerlink" title="工具篇"></a>工具篇</h1><h2 id="Windows"><a href="#Windows" class="headerlink" title="Windows"></a>Windows</h2><p><a target="_blank" rel="noopener" href="https://www.jetbrains.com/dotmemory/">dotmemory</a> 只能检查.net工程。</p>
<p><a target="_blank" rel="noopener" href="https://archive.codeplex.com/?p=vld">vld</a> <a target="_blank" rel="noopener" href="https://kinddragon.github.io/vld/">Visual Leak Detector</a> 代码比较古老，只能支持到vs2015版本。</p>
<p><a target="_blank" rel="noopener" href="https://www.microfocus.com/en-us/products/devpartner/overview">NuMega BoundsChecker</a></p>
<p><a target="_blank" rel="noopener" href="https://www.microsoft.com/en-US/download/details.aspx?id=58210">DebugDial</a> 这个工具是微软出品的。</p>
<p>参考这份文档：<a target="_blank" rel="noopener" href="https://blog.csdn.net/xiaoyafang123/article/details/76589485?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242">使用Debug Diagnostic Tool排除内存泄漏故障</a></p>
<h2 id="Linux"><a href="#Linux" class="headerlink" title="Linux"></a>Linux</h2><p><a target="_blank" rel="noopener" href="https://github.com/gperftools/gperftools">gperftools</a> 非侵入式的内存检查工具。可以通过LD_PRELOAD来设置</p>
<p><a target="_blank" rel="noopener" href="https://www.valgrind.org/">valgrand</a> 非侵入式的内存检查工具。不过对于大项目，不算太友好；需要一台比较好的机器来跑。</p>
<p><a target="_blank" rel="noopener" href="https://clang.llvm.org/">clang</a> Address Sanitizer 工具。</p>
<p>这里我们做了一个例子来演示，它如何检查服务器的内存泄露：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">[root@VM_0_13_centos cpp_leak_sample]<span class="comment"># clang++ -D_GLIBCXX_DEBUG -g -o main -fsanitize=address -std=c++11 ./main.cpp</span></span><br><span class="line">[root@VM_0_13_centos cpp_leak_sample]<span class="comment"># ./main </span></span><br><span class="line"></span><br><span class="line">=================================================================</span><br><span class="line">==28593==ERROR: LeakSanitizer: detected memory leaks</span><br><span class="line"></span><br><span class="line">Direct leak of 4 byte(s) <span class="keyword">in</span> 2 object(s) allocated from:</span><br><span class="line">    <span class="comment">#0 0x526a08 in operator new[](unsigned long) (/root/learn/cpp/cpp_leak_sample/main+0x526a08)</span></span><br><span class="line">    <span class="comment">#1 0x52aeda in main /root/learn/cpp/cpp_leak_sample/./main.cpp:21:19</span></span><br><span class="line">    <span class="comment">#2 0x7f1ddf091554 in __libc_start_main (/lib64/libc.so.6+0x22554)</span></span><br><span class="line"></span><br><span class="line">SUMMARY: AddressSanitizer: 4 byte(s) leaked <span class="keyword">in</span> 2 allocation(s).</span><br><span class="line">[root@VM_0_13_centos cpp_leak_sample]<span class="comment"># vim ./main.cpp </span></span><br><span class="line">[root@VM_0_13_centos cpp_leak_sample]<span class="comment"># clang++ -D_GLIBCXX_DEBUG -g -o main -fsanitize=address -std=c++11 ./main.cpp</span></span><br><span class="line">[root@VM_0_13_centos cpp_leak_sample]<span class="comment"># ./main </span></span><br><span class="line"></span><br><span class="line">=================================================================</span><br><span class="line">==3425==ERROR: LeakSanitizer: detected memory leaks</span><br><span class="line"></span><br><span class="line">Direct leak of 4 byte(s) <span class="keyword">in</span> 2 object(s) allocated from:</span><br><span class="line">    <span class="comment">#0 0x526f88 in operator new[](unsigned long) (/root/learn/cpp/cpp_leak_sample/main+0x526f88)</span></span><br><span class="line">    <span class="comment">#1 0x52b43f in leak_sample1() /root/learn/cpp/cpp_leak_sample/./main.cpp:24:19</span></span><br><span class="line">    <span class="comment">#2 0x52b96a in main /root/learn/cpp/cpp_leak_sample/./main.cpp:63:5</span></span><br><span class="line">    <span class="comment">#3 0x7f769f996554 in __libc_start_main (/lib64/libc.so.6+0x22554)</span></span><br><span class="line"></span><br><span class="line">SUMMARY: AddressSanitizer: 4 byte(s) leaked <span class="keyword">in</span> 2 allocation(s).</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://clang-analyzer.llvm.org/">Clang Static Analyzer</a> 静态分析工具。</p>
<p><a target="_blank" rel="noopener" href="https://clang.llvm.org/docs/UsersManual.html#options-to-control-error-and-warning-messages">clang控制error-warnning信息的选项</a></p>
<p><a target="_blank" rel="noopener" href="https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer">sanitizers的官方wiki</a></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">$ cat suppr.txt </span><br><span class="line"><span class="comment"># This is a known leak.</span></span><br><span class="line">leak:FooBar</span><br><span class="line">$ cat lsan-suppressed.cc </span><br><span class="line"><span class="comment">#include &lt;stdlib.h&gt;</span></span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">FooBar</span></span>() &#123;</span><br><span class="line">  malloc(7);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">Baz</span></span>() &#123;</span><br><span class="line">  malloc(5);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int <span class="function"><span class="title">main</span></span>() &#123;</span><br><span class="line">  FooBar();</span><br><span class="line">  Baz();</span><br><span class="line">  <span class="built_in">return</span> 0;</span><br><span class="line">&#125;</span><br><span class="line">$ clang++ lsan-suppressed.cc -fsanitize=address</span><br><span class="line">$ ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=suppressions=suppr.txt ./a.out</span><br><span class="line"></span><br><span class="line">=================================================================</span><br><span class="line">==26475==ERROR: LeakSanitizer: detected memory leaks</span><br><span class="line"></span><br><span class="line">Direct leak of 5 byte(s) <span class="keyword">in</span> 1 object(s) allocated from:</span><br><span class="line">    <span class="comment">#0 0x44f2de in malloc /usr/home/hacker/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:74</span></span><br><span class="line">    <span class="comment">#1 0x464e86 in Baz() (/usr/home/hacker/a.out+0x464e86)</span></span><br><span class="line">    <span class="comment">#2 0x464fb4 in main (/usr/home/hacker/a.out+0x464fb4)</span></span><br><span class="line">    <span class="comment">#3 0x7f7e760b476c in __libc_start_main /build/buildd/eglibc-2.15/csu/libc-start.c:226</span></span><br><span class="line"></span><br><span class="line">-----------------------------------------------------</span><br><span class="line">Suppressions used:[design document](AddressSanitizerLeakSanitizerDesignDocument)</span><br><span class="line">  count      bytes template</span><br><span class="line">      1          7 FooBar</span><br><span class="line">-----------------------------------------------------</span><br><span class="line"></span><br><span class="line">SUMMARY: AddressSanitizer: 5 byte(s) leaked <span class="keyword">in</span> 1 allocation(s).</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener" href="https://github.com/jemalloc/jemalloc/wiki/Use-Case%3A-Leak-Checking">Jemalloc检查内存泄漏</a></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Jemalloc编译的时候，需要将调试信息开启，否则无法启用检查内存的功能；</span></span><br><span class="line">./configure --enable-log --enable-debug --enable-prof-libunwind --enable-prof CXX=clang++ CC=clang</span><br><span class="line"></span><br><span class="line"><span class="comment"># 参考资料</span></span><br><span class="line"><span class="comment"># : Invalid conf pair: prof:true</span></span><br><span class="line"><span class="comment"># https://github.com/jemalloc/jemalloc/issues/175</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># In all likelihood the jemalloc build you are using didn&#x27;t have --enable-prof specified to the configurescript when it was built. You can verify this via the opt.stats_print mallctl to print out configuration information, or you can query config.prof directly.</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 编译出来的位置</span></span><br><span class="line">/usr/<span class="built_in">local</span>/lib/libjemalloc.so.2</span><br><span class="line">/usr/<span class="built_in">local</span>/lib/libjemalloc.so</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在命令行里面启动服务器gs，增加一些参数，来开始检测内存泄漏</span></span><br><span class="line">MALLOC_CONF=prof_leak:<span class="literal">true</span>,lg_prof_sample:0,prof_final:<span class="literal">true</span> \</span><br><span class="line">LD_PRELOAD=/usr/<span class="built_in">local</span>/lib/libjemalloc.so ./gs</span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> MALLOC_CONF=<span class="string">&quot;prof:true,lg_prof_sample:1,prof_accum:false,prof_prefix:jeprof.out&quot;</span></span><br></pre></td></tr></table></figure>

<p>sanitizers 的内存泄漏检查，是关闭服务器之后才能看到结果。<br>如果是运行期的内存泄漏问题，还是需要通过dump heap来做对比。<br>jemalloc/tcmalloc都能做这样的事情。<br>jeprof可以用来比较两个dump(显示增量部分)：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># /usr/local/jemalloc-5.1.0/bin/jeprof a.out --base=jeprof.34584.2.i2.heap jeprof.34584.3.i3.heap</span></span><br><span class="line">Using <span class="built_in">local</span> file a.out.</span><br><span class="line">Using <span class="built_in">local</span> file jeprof.34584.3.i3.heap.</span><br><span class="line">Welcome to jeprof!  For <span class="built_in">help</span>, <span class="built_in">type</span> <span class="string">&#x27;help&#x27;</span>.</span><br><span class="line">(jeprof) top</span><br><span class="line">Total: 1.6 MB</span><br><span class="line">     1.1  66.2%  66.2%      1.1  66.2% do_something_else</span><br><span class="line">     0.5  33.8% 100.0%      0.5  33.8% do_something</span><br><span class="line">     0.0   0.0% 100.0%      1.6 100.0% __libc_start_main</span><br><span class="line">     0.0   0.0% 100.0%      1.6 100.0% _start</span><br><span class="line">     0.0   0.0% 100.0%      1.6 100.0% main</span><br><span class="line">(jeprof)</span><br><span class="line"></span><br><span class="line">$ jeprof  --show_bytes --pdf ./cpp_leak_sample jeprof.10395.1.i1.heap &gt; a.pdf</span><br></pre></td></tr></table></figure>

<p>最终的效果：</p>
<p><a target="_blank" rel="noopener" href="https://imgtu.com/i/clsxxS"><img src="https://z3.ax1x.com/2021/04/06/clsxxS.png" alt="clsxxS.png"></a></p>
<p>valgrind ./cpp_leak_sample –leak-check=full</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">leak 512 byte</span><br><span class="line">==11344== Mismatched free() / delete / delete []</span><br><span class="line">==11344==    at 0x483CFBF: operator delete(void*) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)</span><br><span class="line">==11344==    by 0x401428: leak_sample2() (cpp_leak_sample.cpp:69)</span><br><span class="line">==11344==    by 0x4014AA: main (cpp_leak_sample.cpp:84)</span><br><span class="line">==11344==  Address 0x4daa360 is 0 bytes inside a block of size 7 alloc&#x27;d</span><br><span class="line">==11344==    at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)</span><br><span class="line">==11344==    by 0x401407: leak_sample2() (cpp_leak_sample.cpp:67)</span><br><span class="line">==11344==    by 0x4014AA: main (cpp_leak_sample.cpp:84)</span><br><span class="line">==11344==</span><br></pre></td></tr></table></figure>

<h1 id="出现过的问题集合"><a href="#出现过的问题集合" class="headerlink" title="出现过的问题集合"></a>出现过的问题集合</h1><p>分配了没有回收。很容易出现的问题，在于容器里面有指针，再清理的时候，没有将容器中的元素清理掉。</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s/uyA5IYH4rasbz5vlT3dmeQ">五大内存泄露应对之策，好文必看！</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://baike.baidu.com/item/LLVM">LLVM百度百科</a></li>
<li>[3] <a target="_blank" rel="noopener" href="https://github.com/google/sanitizers/">GoogleSanitizers</a></li>
<li>[4] <a target="_blank" rel="noopener" href="http://jemalloc.net/">Jemalloc</a></li>
<li>[5] <a target="_blank" rel="noopener" href="https://www.yuanguohuo.com/2019/01/02/jemalloc-heap-profiling/">通过jemalloc检查heap</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/03/29/2021/2021-03-29-C++%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D/" data-id="ckrn3an7g001p20xwboom3p9t" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/C/" rel="tag">C++</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-03-19-python-log" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/03/19/2021/2021-03-19-python-log/" class="article-date">
  <time datetime="2021-03-18T16:00:00.000Z" itemprop="datePublished">2021-03-19</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/03/19/2021/2021-03-19-python-log/">python日志加工</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>分析日志相关的脚本用的比较多。</p>
<h1 id="环境搭建"><a href="#环境搭建" class="headerlink" title="环境搭建"></a>环境搭建</h1><h2 id="python"><a href="#python" class="headerlink" title="python"></a>python</h2><p>Python 3.9.0</p>
<h1 id="实际需要掌握的技巧"><a href="#实际需要掌握的技巧" class="headerlink" title="实际需要掌握的技巧"></a>实际需要掌握的技巧</h1><h2 id="正则表达式"><a href="#正则表达式" class="headerlink" title="正则表达式"></a>正则表达式</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># [18:57:52] [INF] GiftItemLog buy rid: 15909, ID: 601, Type: 6, Rmb: 30</span></span><br><span class="line">re_buy = re.<span class="built_in">compile</span>(<span class="string">&quot;GiftItemLog buy rid: ([0-9_]+), ID: ([0-9_]+), Type: ([0-9_]+), Rmb: ([0-9_]+)&quot;</span>)</span><br></pre></td></tr></table></figure>

<h2 id="按照utf-8来读写文件-按照行读取文件"><a href="#按照utf-8来读写文件-按照行读取文件" class="headerlink" title="按照utf-8来读写文件,按照行读取文件"></a>按照utf-8来读写文件,按照行读取文件</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">c_fd = codecs.<span class="built_in">open</span>(<span class="string">&#x27;./insert_create.sql&#x27;</span>, <span class="string">&#x27;w&#x27;</span>, encoding=<span class="string">&#x27;utf-8&#x27;</span>)</span><br><span class="line"><span class="keyword">with</span> codecs.<span class="built_in">open</span>(<span class="string">&#x27;./2020-04-22.log&#x27;</span>, <span class="string">&#x27;r&#x27;</span>, encoding=<span class="string">&#x27;utf-8&#x27;</span>) <span class="keyword">as</span> fd:</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        line = fd.readline()</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> line: <span class="keyword">break</span></span><br><span class="line">c_fd.close()</span><br></pre></td></tr></table></figure>

<h2 id="写入excel中"><a href="#写入excel中" class="headerlink" title="写入excel中"></a>写入excel中</h2><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1>
      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/03/19/2021/2021-03-19-python-log/" data-id="ckrn3an7e001n20xwe4wyd32f" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/python/" rel="tag">python</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-2021/2021-03-16-recast.crowd笔记" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2021/03/16/2021/2021-03-16-recast.crowd%E7%AC%94%E8%AE%B0/" class="article-date">
  <time datetime="2021-03-15T16:00:00.000Z" itemprop="datePublished">2021-03-16</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2021/03/16/2021/2021-03-16-recast.crowd%E7%AC%94%E8%AE%B0/">RecastCrowd笔记</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>开始阅读一下recast-crowds相关知识，这个功能是避免怪物在跑动的时候，挤在一块。先从数据结构开始了解。</p>
<p><a target="_blank" rel="noopener" href="http://gamma.cs.unc.edu/RVO/icra2008.wmv">RVO视频参考</a></p>
<p>每个agent都认为其他的agent都会移动；</p>
<p>agent在接近其他agent的时候，速度会变慢，甚至能停止；</p>
<p>当拥挤的时候，将会先尝试自己指向最近的寻路点连线向量$\vec{a}$，是否存在碰撞；</p>
<p>如果有碰撞，先减速，将$\vec{a}$向量±45°做短距离移动；</p>
<p>源码中通过@ingroup来做分类。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// @ingroup crowd</span></span><br></pre></td></tr></table></figure>

<p>具体工程：</p>
<p>DetourCrowd</p>
<h1 id="初步阅读"><a href="#初步阅读" class="headerlink" title="初步阅读"></a>初步阅读</h1><h2 id="概念罗列"><a href="#概念罗列" class="headerlink" title="概念罗列"></a>概念罗列</h2><h3 id="名词解释"><a href="#名词解释" class="headerlink" title="名词解释"></a>名词解释</h3><p>里面使用了一些概念：</p>
<table>
<thead>
<tr>
<th align="left">单词</th>
<th align="left">释义</th>
<th align="left">备注</th>
</tr>
</thead>
<tbody><tr>
<td align="left">bound</td>
<td align="left">限制</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">Boundary</td>
<td align="left">边界</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">convex</td>
<td align="left">凸多边形</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">volume</td>
<td align="left">卷，大量</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">avoidance</td>
<td align="left">避免，逃避；废止</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">Segment</td>
<td align="left">段，部分</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">Poly</td>
<td align="left">多边形</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">Corner</td>
<td align="left">角落</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">Topology</td>
<td align="left">拓扑</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">purge</td>
<td align="left">清理</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">steering</td>
<td align="left">导航</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">corridor</td>
<td align="left">走廊</td>
<td align="left"></td>
</tr>
<tr>
<td align="left">segment</td>
<td align="left">段</td>
<td align="left"></td>
</tr>
</tbody></table>
<h2 id="文件清单"><a href="#文件清单" class="headerlink" title="文件清单"></a>文件清单</h2><h3 id="DetourCrowd-文件"><a href="#DetourCrowd-文件" class="headerlink" title="DetourCrowd 文件"></a>DetourCrowd 文件</h3><p>限定：</p>
<p>为转向决定，提供的最大的相邻对象</p>
<h4 id="class-dtCrowd"><a href="#class-dtCrowd" class="headerlink" title="class dtCrowd"></a>class dtCrowd</h4><p>对外提供对于一组 dtCrowdAgent 管理的类。</p>
<p>成员</p>
<figure class="highlight hpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> m_maxAgents;<span class="comment">// 最大代理数目</span></span><br><span class="line">dtCrowdAgent* m_agents;<span class="comment">// 当前持有的代理</span></span><br><span class="line">dtCrowdAgent** m_activeAgents;<span class="comment">// 激活的代理</span></span><br><span class="line">dtCrowdAgentAnimation* m_agentAnims;<span class="comment">// 代理动画</span></span><br><span class="line"></span><br><span class="line">dtPathQueue m_pathq;<span class="comment">// 寻路队列</span></span><br><span class="line"></span><br><span class="line">dtObstacleAvoidanceParams m_obstacleQueryParams[DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS];<span class="comment">//阻挡寻路参数</span></span><br><span class="line">dtObstacleAvoidanceQuery* m_obstacleQuery;<span class="comment">//阻挡寻路</span></span><br><span class="line"></span><br><span class="line">dtProximityGrid* m_grid;<span class="comment">// 近似单元格</span></span><br><span class="line"></span><br><span class="line">dtPolyRef* m_pathResult;<span class="comment">// 寻路面片集合</span></span><br><span class="line"><span class="keyword">int</span> m_maxPathResult;<span class="comment">// 最大面片数目</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">float</span> m_agentPlacementHalfExtents[<span class="number">3</span>];</span><br><span class="line"></span><br><span class="line">dtQueryFilter m_filters[DT_CROWD_MAX_QUERY_FILTER_TYPE];<span class="comment">// 查询过滤器</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">float</span> m_maxAgentRadius;<span class="comment">// 最大的代理对象的半径</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> m_velocitySampleCount;<span class="comment">// 速度样本数</span></span><br><span class="line"></span><br><span class="line">dtNavMeshQuery* m_navquery;<span class="comment">// 导航寻路对象</span></span><br></pre></td></tr></table></figure>

<p>私有函数：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 更新拓扑优化</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">updateTopologyOptimization</span><span class="params">(dtCrowdAgent** agents, <span class="keyword">const</span> <span class="keyword">int</span> nagents, <span class="keyword">const</span> <span class="keyword">float</span> dt)</span></span>;</span><br><span class="line"><span class="comment">// 更新移动请求</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">updateMoveRequest</span><span class="params">(<span class="keyword">const</span> <span class="keyword">float</span> dt)</span></span>;</span><br><span class="line"><span class="comment">// 检查路径的有效性</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">checkPathValidity</span><span class="params">(dtCrowdAgent** agents, <span class="keyword">const</span> <span class="keyword">int</span> nagents, <span class="keyword">const</span> <span class="keyword">float</span> dt)</span></span>;</span><br><span class="line"><span class="comment">// 获取代理的index</span></span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">int</span> <span class="title">getAgentIndex</span><span class="params">(<span class="keyword">const</span> dtCrowdAgent* agent)</span> <span class="keyword">const</span>  </span>&#123; <span class="keyword">return</span> (<span class="keyword">int</span>)(agent - m_agents); &#125;</span><br><span class="line"><span class="comment">// 请求重新设定移动目标位置</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">requestMoveTargetReplan</span><span class="params">(<span class="keyword">const</span> <span class="keyword">int</span> idx, dtPolyRef ref, <span class="keyword">const</span> <span class="keyword">float</span>* pos)</span></span>;</span><br><span class="line"><span class="comment">// 清理</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">purge</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>

<p>公用函数：</p>
<figure class="highlight hpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 初始化crowd对象，新建一批agent，设置agent的半径，设置寻路对象；</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">init</span><span class="params">(<span class="keyword">const</span> <span class="keyword">int</span> maxAgents, <span class="keyword">const</span> <span class="keyword">float</span> maxAgentRadius, dtNavMesh* nav)</span></span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h4 id="struct-dtCrowdAgent"><a href="#struct-dtCrowdAgent" class="headerlink" title="struct dtCrowdAgent"></a>struct dtCrowdAgent</h4><p>被 dtCrowd 管理的单个 agent 对象</p>
<figure class="highlight hpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/// True if the agent is active, false if the agent is in an unused slot in the agent pool.</span></span><br><span class="line"><span class="keyword">bool</span> active;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> state;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the requested position, else false.</span></span><br><span class="line"><span class="keyword">bool</span> partial;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The path corridor the agent is using.</span></span><br><span class="line">dtPathCorridor corridor;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The local boundary data for the agent.</span></span><br><span class="line">dtLocalBoundary boundary;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// Time since the agent&#x27;s path corridor was optimized.</span></span><br><span class="line"><span class="keyword">float</span> topologyOptTime;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The known neighbors of the agent.</span></span><br><span class="line">dtCrowdNeighbour neis[DT_CROWDAGENT_MAX_NEIGHBOURS];</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The number of neighbors.</span></span><br><span class="line"><span class="keyword">int</span> nneis;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The desired speed.</span></span><br><span class="line"><span class="keyword">float</span> desiredSpeed;</span><br><span class="line"></span><br><span class="line"><span class="keyword">float</span> npos[<span class="number">3</span>];    <span class="comment">///&lt; The current agent position. [(x, y, z)]</span></span><br><span class="line"><span class="keyword">float</span> disp[<span class="number">3</span>];    <span class="comment">///&lt; A temporary value used to accumulate agent displacement during iterative collision resolution. [(x, y, z)]</span></span><br><span class="line"><span class="keyword">float</span> dvel[<span class="number">3</span>];    <span class="comment">///&lt; The desired velocity of the agent. Based on the current path, calculated from scratch each frame. [(x, y, z)]</span></span><br><span class="line"><span class="keyword">float</span> nvel[<span class="number">3</span>];    <span class="comment">///&lt; The desired velocity adjusted by obstacle avoidance, calculated from scratch each frame. [(x, y, z)]</span></span><br><span class="line"><span class="keyword">float</span> vel[<span class="number">3</span>];    <span class="comment">///&lt; The actual velocity of the agent. The change from nvel -&gt; vel is constrained by max acceleration. [(x, y, z)]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/// The agent&#x27;s configuration parameters.</span></span><br><span class="line">dtCrowdAgentParams params;</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The local path corridor corners for the agent. (Staight path.) [(x, y, z) * #ncorners]</span></span><br><span class="line"><span class="keyword">float</span> cornerVerts[DT_CROWDAGENT_MAX_CORNERS*<span class="number">3</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The local path corridor corner flags. (See: #dtStraightPathFlags) [(flags) * #ncorners]</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> cornerFlags[DT_CROWDAGENT_MAX_CORNERS];</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The reference id of the polygon being entered at the corner. [(polyRef) * #ncorners]</span></span><br><span class="line">dtPolyRef cornerPolys[DT_CROWDAGENT_MAX_CORNERS];</span><br><span class="line"></span><br><span class="line"><span class="comment">/// The number of corners.</span></span><br><span class="line"><span class="keyword">int</span> ncorners;</span><br><span class="line"></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> targetState;      <span class="comment">///&lt; State of the movement request.</span></span><br><span class="line"><span class="comment">// enum MoveRequestState</span></span><br><span class="line"><span class="comment">// &#123;</span></span><br><span class="line"><span class="comment">//  DT_CROWDAGENT_TARGET_NONE = 0,</span></span><br><span class="line"><span class="comment">//  DT_CROWDAGENT_TARGET_FAILED,</span></span><br><span class="line"><span class="comment">//  DT_CROWDAGENT_TARGET_VALID,</span></span><br><span class="line"><span class="comment">//  DT_CROWDAGENT_TARGET_REQUESTING,</span></span><br><span class="line"><span class="comment">//  DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE,</span></span><br><span class="line"><span class="comment">//  DT_CROWDAGENT_TARGET_WAITING_FOR_PATH,</span></span><br><span class="line"><span class="comment">//  DT_CROWDAGENT_TARGET_VELOCITY,</span></span><br><span class="line"><span class="comment">//&#125;;</span></span><br><span class="line">dtPolyRef targetRef;        <span class="comment">///&lt; Target polyref of the movement request.</span></span><br><span class="line"><span class="keyword">float</span> targetPos[<span class="number">3</span>];          <span class="comment">///&lt; Target position of the movement request (or velocity in case of DT_CROWDAGENT_TARGET_VELOCITY).</span></span><br><span class="line">dtPathQueueRef targetPathqRef;    <span class="comment">///&lt; Path finder ref.</span></span><br><span class="line"><span class="keyword">bool</span> targetReplan;          <span class="comment">///&lt; Flag indicating that the current path is being replanned.</span></span><br><span class="line"><span class="keyword">float</span> targetReplanTime;        <span class="comment">/// &lt;Time since the agent&#x27;s target was replanned.</span></span><br></pre></td></tr></table></figure>

<h4 id="struct-dtCrowdAgentParams"><a href="#struct-dtCrowdAgentParams" class="headerlink" title="struct dtCrowdAgentParams"></a>struct dtCrowdAgentParams</h4><p>dtCrowdAgent 的配置参数。</p>
<figure class="highlight hpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// Configuration parameters for a crowd agent.</span></span><br><span class="line"><span class="comment">/// @ingroup crowd</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">dtCrowdAgentParams</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">  <span class="keyword">float</span> radius;            <span class="comment">///&lt; Agent radius. [Limit: &gt;= 0]</span></span><br><span class="line">  <span class="keyword">float</span> height;            <span class="comment">///&lt; Agent height. [Limit: &gt; 0]</span></span><br><span class="line">  <span class="keyword">float</span> maxAcceleration;        <span class="comment">///&lt; Maximum allowed acceleration. [Limit: &gt;= 0]</span></span><br><span class="line">  <span class="keyword">float</span> maxSpeed;            <span class="comment">///&lt; Maximum allowed speed. [Limit: &gt;= 0]</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: &gt; 0]</span></span><br><span class="line">  <span class="keyword">float</span> collisionQueryRange;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">float</span> pathOptimizationRange;    <span class="comment">///&lt; The path visibility optimization range. [Limit: &gt; 0]</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: &gt;= 0]</span></span><br><span class="line">  <span class="keyword">float</span> separationWeight;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/// Flags that impact steering behavior. (See: #UpdateFlags)</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">char</span> updateFlags;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/// The index of the avoidance configuration to use for the agent. </span></span><br><span class="line">  <span class="comment">/// [Limits: 0 &lt;= value &lt;= #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">char</span> obstacleAvoidanceType;  </span><br><span class="line"></span><br><span class="line">  <span class="comment">/// The index of the query filter used by this agent.</span></span><br><span class="line">  <span class="keyword">unsigned</span> <span class="keyword">char</span> queryFilterType;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/// User defined data attached to the agent.</span></span><br><span class="line">  <span class="keyword">void</span>* userData;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h4 id="struct-dtCrowdNeighbour"><a href="#struct-dtCrowdNeighbour" class="headerlink" title="struct dtCrowdNeighbour"></a>struct dtCrowdNeighbour</h4><p>提供 neighbor 数据给 agents 管理。</p>
<p>idx neighor 在 crowd 的index编号。<br>dist agent neighbor 的距离。</p>
<h4 id="enum-CrowdAgentState"><a href="#enum-CrowdAgentState" class="headerlink" title="enum CrowdAgentState"></a>enum CrowdAgentState</h4><p>/// The type of navigation mesh polygon the agent is currently traversing.<br>/// @ingroup crowd<br>enum CrowdAgentState<br>{<br>    DT_CROWDAGENT_STATE_INVALID,        ///&lt; The agent is not in a valid state.<br>    DT_CROWDAGENT_STATE_WALKING,        ///&lt; The agent is traversing a normal navigation mesh polygon.<br>    DT_CROWDAGENT_STATE_OFFMESH,        ///&lt; The agent is traversing an off-mesh connection.<br>};</p>
<h4 id="enum-MoveRequestState"><a href="#enum-MoveRequestState" class="headerlink" title="enum MoveRequestState"></a>enum MoveRequestState</h4><p>enum MoveRequestState<br>{<br>    DT_CROWDAGENT_TARGET_NONE = 0,<br>    DT_CROWDAGENT_TARGET_FAILED,<br>    DT_CROWDAGENT_TARGET_VALID,<br>    DT_CROWDAGENT_TARGET_REQUESTING,<br>    DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE,<br>    DT_CROWDAGENT_TARGET_WAITING_FOR_PATH,<br>    DT_CROWDAGENT_TARGET_VELOCITY,<br>};</p>
<h3 id="DetourLocalBoundary-文件"><a href="#DetourLocalBoundary-文件" class="headerlink" title="DetourLocalBoundary 文件"></a>DetourLocalBoundary 文件</h3><h3 id="DetourObstacleAvoidance-文件"><a href="#DetourObstacleAvoidance-文件" class="headerlink" title="DetourObstacleAvoidance 文件"></a>DetourObstacleAvoidance 文件</h3><h4 id="struct-dtObstacleAvoidanceParams"><a href="#struct-dtObstacleAvoidanceParams" class="headerlink" title="struct dtObstacleAvoidanceParams"></a>struct dtObstacleAvoidanceParams</h4><p>成员：</p>
<figure class="highlight hpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> velBias;<span class="comment">// 运动偏向</span></span><br><span class="line"><span class="keyword">float</span> weightDesVel;<span class="comment">// </span></span><br><span class="line"><span class="keyword">float</span> weightCurVel;</span><br><span class="line"><span class="keyword">float</span> weightSide;</span><br><span class="line"><span class="keyword">float</span> weightToi;<span class="comment">// </span></span><br><span class="line"><span class="keyword">float</span> horizTime;<span class="comment">// 水平时间</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> gridSize;  <span class="comment">///&lt; grid</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> adaptiveDivs;  <span class="comment">///&lt; adaptive</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> adaptiveRings;  <span class="comment">///&lt; adaptive</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span> adaptiveDepth;  <span class="comment">///&lt; adaptive</span></span><br></pre></td></tr></table></figure>

<h3 id="DetourPathCorridor-文件"><a href="#DetourPathCorridor-文件" class="headerlink" title="DetourPathCorridor 文件"></a>DetourPathCorridor 文件</h3><h3 id="DetourPathQueue-文件"><a href="#DetourPathQueue-文件" class="headerlink" title="DetourPathQueue 文件"></a>DetourPathQueue 文件</h3><h4 id="class-dtPathQueue"><a href="#class-dtPathQueue" class="headerlink" title="class dtPathQueue"></a>class dtPathQueue</h4><p>寻路队列；</p>
<h4 id="struct-PathQuery"><a href="#struct-PathQuery" class="headerlink" title="struct PathQuery"></a>struct PathQuery</h4><h3 id="DetourProximityGrid-文件"><a href="#DetourProximityGrid-文件" class="headerlink" title="DetourProximityGrid 文件"></a>DetourProximityGrid 文件</h3><h2 id="主流程梳理"><a href="#主流程梳理" class="headerlink" title="主流程梳理"></a>主流程梳理</h2><h3 id="dwCrowd-update"><a href="#dwCrowd-update" class="headerlink" title="dwCrowd::update"></a>dwCrowd::update</h3><p>细读update函数：</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 每一帧都在调用的函数。</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dtCrowd::update</span><span class="params">(<span class="keyword">const</span> <span class="keyword">float</span> dt, dtCrowdAgentDebugInfo* debug)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">  <span class="comment">// 先将本组全部的 agent 获取出来。</span></span></span><br><span class="line"><span class="function">  <span class="keyword">int</span> <span class="title">dtCrowd::getActiveAgents</span><span class="params">(dtCrowdAgent** agents, <span class="keyword">const</span> <span class="keyword">int</span> maxAgents)</span></span>&#123;...&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 检查全部的 agent 还有合法的寻路路点；</span></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">dtCrowd::checkPathValidity</span><span class="params">(dtCrowdAgent** agents, <span class="keyword">const</span> <span class="keyword">int</span> nagents, <span class="keyword">const</span> <span class="keyword">float</span> dt)</span></span>&#123;...&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 更新同步移动请求和寻路对象</span></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">dtCrowd::updateMoveRequest</span><span class="params">(<span class="keyword">const</span> <span class="keyword">float</span> )</span></span>&#123;...&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 优化拓扑</span></span><br><span class="line">  <span class="function"><span class="keyword">void</span> <span class="title">dtCrowd::updateTopologyOptimization</span><span class="params">(dtCrowdAgent** agents, <span class="keyword">const</span> <span class="keyword">int</span> nagents, <span class="keyword">const</span> <span class="keyword">float</span> dt)</span></span>&#123;...&#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 将agents注册到 proximity grid </span></span><br><span class="line">  <span class="comment">// 其实就是获取当前的agent对象的pos，radius，计算一个正方形，添加到 proximity grid 中。</span></span><br><span class="line">  <span class="comment">// 可以理解成栅格化；</span></span><br><span class="line">    dtProximityGrid::addItem</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取全部 agent 靠近的 navmesh segments，其实也会将 agent 的 neighbours 都重新生成</span></span><br><span class="line">  <span class="comment">// Get nearby navmesh segments and agents to collide with.</span></span><br><span class="line">    <span class="comment">// 检查 agent 状态需要是 DT_CROWDAGENT_STATE_WALKING</span></span><br><span class="line">    <span class="keyword">if</span> (ag-&gt;state != DT_CROWDAGENT_STATE_WALKING)</span><br><span class="line">    <span class="comment">// 当 agent collision boundary 无效了或者确定距离通过了，将更新 collision boundary。</span></span><br><span class="line">    <span class="comment">// 先计算一个标准量，读取 agent collisionQueryRange</span></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">float</span> updateThr = ag-&gt;params.collisionQueryRange*<span class="number">0.25f</span>;</span><br><span class="line">    <span class="comment">// 计算自己位置是否超出了 boundary 的区间</span></span><br><span class="line">    <span class="built_in">dtVdist2DSqr</span>(ag-&gt;npos, ag-&gt;boundary.<span class="built_in">getCenter</span>()) &gt; <span class="built_in">dtSqr</span>(updateThr)</span><br><span class="line">    <span class="comment">// 检查 boundary 是否还合法</span></span><br><span class="line">    !ag-&gt;boundary.<span class="built_in">isValid</span>(m_navquery, &amp;m_filters[ag-&gt;params.queryFilterType])</span><br><span class="line">      <span class="comment">// 检测 Boundary 是否合法</span></span><br><span class="line">      <span class="function"><span class="keyword">bool</span> <span class="title">dtLocalBoundary::isValid</span><span class="params">(dtNavMeshQuery* navquery, <span class="keyword">const</span> dtQueryFilter* filter)</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 更新 boundary.update</span></span></span><br><span class="line"><span class="function">      ag-&gt;boundary.update</span></span><br><span class="line"><span class="function">    <span class="comment">// 获取 agent 的 neighbour agents</span></span></span><br><span class="line"><span class="function">    <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">getNeighbours</span><span class="params">()</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 从 dtProximityGrid::queryItems()</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 通过近似格子获取附近的agents对象。</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 循环全部的附近 agent</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 检查高度是否相差太大</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 检查距离是否太远</span></span></span><br><span class="line"><span class="function">      <span class="comment">// static int addNeighbour()</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 写入 agent.neis 数组中</span></span></span><br><span class="line"><span class="function">  <span class="comment">// 循环全部的 agent 可以到 corner</span></span></span><br><span class="line"><span class="function">  <span class="comment">// Find next corner to steer to.</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 检查 agent.state 是否 DT_CROWDAGENT_STATE_WALKING</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 检查 agent.targetState 为 DT_CROWDAGENT_TARGET_NONE DT_CROWDAGENT_TARGET_VELOCITY</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">    <span class="comment">// int dtPathCorridor::findCorners</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 类似 dtNavMeshQuery::findStraightPath 函数</span></span></span><br><span class="line"><span class="function">    <span class="keyword">int</span> <span class="title">findCorners</span><span class="params">(<span class="keyword">float</span>* cornerVerts, <span class="keyword">unsigned</span> <span class="keyword">char</span>* cornerFlags, dtPolyRef* cornerPolys, <span class="keyword">const</span> <span class="keyword">int</span> maxCorners, dtNavMeshQuery* navquery, <span class="keyword">const</span> dtQueryFilter* filter)</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 最多收集4步</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">  <span class="comment">// 根据配置，检查是否开启了优化，将会直接将下一个 corner 裁剪掉。</span></span></span><br><span class="line"><span class="function">  <span class="comment">// Find next corner to steer to.</span></span></span><br><span class="line"><span class="function">    <span class="keyword">void</span> <span class="title">optimizePathVisibility</span><span class="params">(<span class="keyword">const</span> <span class="keyword">float</span>* next, <span class="keyword">const</span> <span class="keyword">float</span> pathOptimizationRange, dtNavMeshQuery* navquery, <span class="keyword">const</span> dtQueryFilter* filter)</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">    <span class="comment">// 后续将会为输出日志，拷贝一些数据。</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 将导航路径开始位置，结束位置写入debug对象中。</span></span></span><br><span class="line"><span class="function">  </span></span><br><span class="line"><span class="function">  <span class="comment">// 循环全部的 agent 触发跳跃点连接，直接将 mesh 连接到一块。</span></span></span><br><span class="line"><span class="function">  <span class="comment">// Trigger off-mesh connections (depends on corners).</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 触发器的 2.25f 范围</span></span></span><br><span class="line"><span class="function">    <span class="keyword">bool</span> <span class="title">overOffmeshConnection</span><span class="params">(<span class="keyword">const</span> dtCrowdAgent* ag, <span class="keyword">const</span> <span class="keyword">float</span> radius)</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 跳跃点</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">  <span class="comment">// 计算转向</span></span></span><br><span class="line"><span class="function">  <span class="comment">// Calculate steering.</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 如果无需转向就全速前进</span></span></span><br><span class="line"><span class="function">    <span class="title">if</span> <span class="params">(ag-&gt;targetState == DT_CROWDAGENT_TARGET_VELOCITY)</span></span></span><br><span class="line"><span class="function">    <span class="comment">// 否则</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 检查是否开启了 Anticipate Turns ，预判转弯</span></span></span><br><span class="line"><span class="function">        <span class="comment">// 进行更加圆滑的转弯</span></span></span><br><span class="line"><span class="function">        <span class="keyword">void</span> <span class="title">calcSmoothSteerDirection</span><span class="params">(<span class="keyword">const</span> dtCrowdAgent* ag, <span class="keyword">float</span>* dir)</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 否则</span></span></span><br><span class="line"><span class="function">        <span class="comment">// 直接转弯</span></span></span><br><span class="line"><span class="function">        <span class="keyword">void</span> <span class="title">calcStraightSteerDirection</span><span class="params">(<span class="keyword">const</span> dtCrowdAgent* ag, <span class="keyword">float</span>* dir)</span></span></span><br><span class="line"><span class="function">      <span class="comment">// 如果快到终点（2倍于自己的半径）的时候，将会让 agent 减速；</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">  <span class="comment">// 计算速度</span></span></span><br><span class="line"><span class="function">  <span class="comment">// Velocity planning.	</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function">  <span class="comment">// 循环全部的 agent 计算转向。</span></span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"></span></span><br></pre></td></tr></table></figure>

<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>多阅读别人的代码，学会如何程序如何去做框架。</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul>
<li>[1] <a target="_blank" rel="noopener" href="https://blog.csdn.net/hjssss/category_8638342.html">Recast源码</a></li>
<li>[2] <a target="_blank" rel="noopener" href="https://www.pianshen.com/article/8639807482/">dtCrowd::update源码阅读</a></li>
<li>[3] <a target="_blank" rel="noopener" href="http://gamma.cs.unc.edu/RVO/">RVO障碍物规避算法</a></li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://example.com/2021/03/16/2021/2021-03-16-recast.crowd%E7%AC%94%E8%AE%B0/" data-id="ckrn3an7d001l20xwczq35qgh" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Game/" rel="tag">Game</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/recast/" rel="tag">recast</a></li></ul>

    </footer>
  </div>
  
</article>


  


  <nav id="page-nav">
    
    <span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><span class="space">&hellip;</span><a class="page-number" href="/page/5/">5</a><a class="extend next" rel="next" href="/page/2/">Next &amp;raquo;</a>
  </nav>

</section>
        
          <aside id="sidebar">
  
    

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/tags/3D/" rel="tag">3D</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/AI/" rel="tag">AI</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/C/" rel="tag">C++</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Game/" rel="tag">Game</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Go/" rel="tag">Go</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Linux/" rel="tag">Linux</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Math/" rel="tag">Math</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Server/" rel="tag">Server</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Unreal-Engine4/" rel="tag">Unreal Engine4</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/" rel="tag">git</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/golang/" rel="tag">golang</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/guitar/" rel="tag">guitar</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/node-js/" rel="tag">node.js</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/" rel="tag">protobuf</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/python/" rel="tag">python</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/recast/" rel="tag">recast</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/" rel="tag">redis</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/type/" rel="tag">type</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/vscode/" rel="tag">vscode</a></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/%E8%BF%90%E7%BB%B4/" rel="tag">运维</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/3D/" style="font-size: 10px;">3D</a> <a href="/tags/AI/" style="font-size: 11.67px;">AI</a> <a href="/tags/C/" style="font-size: 15px;">C++</a> <a href="/tags/Game/" style="font-size: 18.33px;">Game</a> <a href="/tags/Go/" style="font-size: 13.33px;">Go</a> <a href="/tags/Linux/" style="font-size: 13.33px;">Linux</a> <a href="/tags/Math/" style="font-size: 11.67px;">Math</a> <a href="/tags/Server/" style="font-size: 16.67px;">Server</a> <a href="/tags/Unreal-Engine4/" style="font-size: 10px;">Unreal Engine4</a> <a href="/tags/git/" style="font-size: 10px;">git</a> <a href="/tags/golang/" style="font-size: 20px;">golang</a> <a href="/tags/guitar/" style="font-size: 10px;">guitar</a> <a href="/tags/node-js/" style="font-size: 10px;">node.js</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/python/" style="font-size: 10px;">python</a> <a href="/tags/recast/" style="font-size: 11.67px;">recast</a> <a href="/tags/redis/" style="font-size: 10px;">redis</a> <a href="/tags/type/" style="font-size: 10px;">type</a> <a href="/tags/vscode/" style="font-size: 10px;">vscode</a> <a href="/tags/%E8%BF%90%E7%BB%B4/" style="font-size: 16.67px;">运维</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/06/">June 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/04/">April 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/03/">March 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/01/">January 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/12/">December 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2020/11/">November 2020</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/03/">March 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/11/">November 2018</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/07/19/2021/2021-07-19-etcd-learn/">go-etcd阅读笔记</a>
          </li>
        
          <li>
            <a href="/2021/07/19/2021/2021-07-19-socketop-learn/">REUSEPORT-REUSEADDR-学习</a>
          </li>
        
          <li>
            <a href="/2021/06/22/2021/2021-06-22-go-ethereum-learn/">go-ethereum阅读笔记</a>
          </li>
        
          <li>
            <a href="/2021/06/21/2021/2021-06-21-server%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/">server测试工具</a>
          </li>
        
          <li>
            <a href="/2021/06/09/2021/2021-06-09-pprof-doc/">go-pprof</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2021 Abel Sean<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>


  
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css">

  
<script src="/fancybox/jquery.fancybox.pack.js"></script>




<script src="/js/script.js"></script>




  </div>
</body>
</html>